La génération d'un niveau se fait en plusieurs étapes :
\begin{itemize}
\item Récupération des fichiers MIDI
\item Conversion du fichier MIDI binaire en fichier texte
\item Analyse ligne par ligne du fichier obtenu
\item Structuration des données
\item Choix de la chanson et de la piste à jouer
\item Création d'une nouvelle instance d'attracteur pour chaque nouvelle note
\item Activation de la première cible
\item Décollage !
\end{itemize}

\subsection{Récupération des fichiers MIDI}
Au lancement du jeu, le dossier ``midi'' est parcouru et tous les fichiers portant l'extension ``.mid'' sont récupérés.
\subsection{Conversion du fichier MIDI binaire en fichier texte}
La conversion du fichier binaire (song.mid) en fichier texte (song.tmid) se fait grâce à l'exécutable ``midiToText.exe''\footnote{Cet exécutable est disponible sur le site \url{http://jlp31.free.fr/cvware/index.html}}.
La structure du format de sortie est très proche de la structure binaire. Chaque ligne représente un ``bloc''\footnote{voir \ref{sec:midistruct}} avec parfois quelques informations textuelles supplémentaires.

Un ``meta event'' de modification de tempo\footnote{voir figure \ref{img:midi_tempo}} est représenté dans la figure \ref{txt:metatempo}

Cette solution n'est pas la plus optimale car elle rajoute une étape supplémentaire qui aurait pu être évitée si l'analyse se faisait directement par lecture du fichier binaire. De plus, l'utilisation d'un exécutable uniquement compatible avec Windows empêche l'éventuelle portabilité sur Mac, Linux, web ou Mobile, mais le code est structuré de façon à être facilement modifiable pour changer cela. Seules les classes \verb?MidiLine? et \verb?MidiSequence? devront êtres modifiés.

\begin{figure}[htbp]
\begin{center}
\begin{verbatim}
dt 0 /* meta: SET-TEMPO */ FFh 51h #(07h A1h 00h)
\end{verbatim}
\begin{itemize}
\item \textbf{dt 0 :} delta time = 0
\item \textbf{/* \dots */ :} informations textuelles
\item \textbf{FFh :} id du bloc = meta-event (le ``h'' signifie juste que le chiffre est en hexadécimal)
\item \textbf{51h :} type = set-tempo
\item \textbf{\#(07h A1h 00h) :} MPQN = 0x07A100 (soit BPM = 120)
\end{itemize}
\caption{Bloc meta ``set-tempo'' en version texte}
\label{txt:metatempo}
\end{center}
\end{figure}

\subsection{Analyse ligne par ligne du fichier obtenu}
A chaque ligne lue, un objet \verb?MidiLine? est créé. La fonction \verb?int MidiLine.parse(string line)? récupère l'identifiant du bloc et parse la ligne en fonction pour remplir une table de hachage dont la structure sera annoncé par la constante qu'elle retourne.

Par exemple, la figure \ref{code:metatempo} représente un extrait de code dans le cas ou la ligne correspond à une meta de type ``set-tempo''\footnote{voir figure \ref{txt:metatempo}}

\begin{figure}[htbp]
\begin{center}
\begin{verbatim}
if (splited[3] == "51h")
{
infos["name"] = "tempo";
infos["time"] = midiToSolfegeTimeFormat(float.Parse(splited[1]));
int content = hexMPQNtoIntBPM(splited[4] + splited[5] + splited[6]);
infos["value"] = content;
return TEMPO;
}
\end{verbatim}
\caption{Bloc meta ``set-tempo'' parsé par la fonction ``MidiLine.parse(string line)''}
\label{code:metatempo}
\end{center}
\end{figure}

\paragraph{Modulation du pitch :}
\label{sec:pitch}
Unity n'étant pas capable de générer des sons à partir d'instructions MIDI, la solution pour jouer une note précise a donc été de moduler la fréquence d'un clip audio analogique de référence.

Grâce au fait que la musique et les mathématiques font bon ménage, il est possible de calculer la fréquence de n'importe quelle note à partir d'une note de référence (voir figure \ref{form:freq}).

Ensuite, si la fréquence du clip audio à moduler est connue, ainsi que son numéro\footnote{voir figure \ref{img:calc_notes}}, la formule de la figure \ref{form:pitch} permet d'obtenir la valeur du pitch à appliquer au clip pour obtenir la note souhaitée.

Dans les paramètres actuels du jeu, la note de référence pour calculer les fréquences est ``A0'' (LA-1) et sa fréquence est de 27.5Hz. Le clip audio de référence quand à lui est un ``A6'' (LA5) d'intensité continu\footnote{le son n'a pas d'attaque ni de maintient}. Sa fréquence de 1760Hz est saisie comme fréquence de référence pour le calcul du pitch.

La raison de ce choix est simplement due à cause du fait que le pitch ne peut pas être supérieur à 3 dans Unity. Il a donc fallut choisir une fréquence de référence élevée pour ne jamais avoir à dépasser cette valeur.

\begin{figure}[htbp]
\begin{center}
\begin{equation}
F(n) = F_{ref} \times 2^{\frac{n-N_{ref}}{12}}
\end{equation}
\caption{Calcul de la fréquence d'une note}
\label{form:freq}
\end{center}
\end{figure}

\begin{figure}[htbp]
\begin{center}
\begin{equation}
P(n) = F(n) / F_{ref}
\end{equation}
\caption{Calcul du pitch d'une note}
\label{form:pitch}
\end{center}
\end{figure}

\paragraph{Conversion du temps :}
La fonction \verb?MidiLine.midiToSolfegeTimeFormat(float time)? transforme l'échelle de temps de façon à ce qu'elle soit relative à la durée d'une ``noire'' (dans un fichier midi, la durée d'une noire vaut 96).
\begin{itemize}
\item \dots
\item double croche = 0.25
\item croche = 0.5
\item noire = 1
\item blanche = 2
\item \dots
\end{itemize}

\paragraph{Conversion du tempo :}
Le tempo est exprimé en MPQN\footnote{Microseconds Per Quarter-Note}. Pour obtenir la valeur en BPM\footnote{Beat Per Minute}, il suffit d'appliquer la formule de la figure \ref{form:tempo}.

\subsection{Structuration des données}
Pour chaque fichier midi, le script de génération créé une instance de \verb?MidiSequence? et appelle sa fonction \verb?MidiSequence.parseSoundFile(string tmidPath)?.

C'est cette fonction qui pour chaque ligne du fichier \verb?<song>.tmid?. appelle la fonction \verb?MidiLine.parse(string line)? et se met à jour en fonction du résultat obtenu. Les informations contenues dans l'objet \verb?MidiSequence? sont les suivantes :

\paragraph{Informations générales :}
Toutes les informations générales de la chanson sont stockées dans la \verb?Hashtable MidiSequence.infos?.

\paragraph{Les pistes :}
Les pistes sont stockées dans la \verb?ArrayList MidiSequence.tracks?. Chaque piste contient une table d'informations (ex : ``trackname'') et une table qui contient les notes. Si lors du parsage, la fin de la piste est atteinte et qu'elle ne contient pas de note, elle est supprimée.

\paragraph{Les modificateurs de piste :}
A chaque fois qu'un modificateur est capturé, il s'applique à toutes les notes qui suivent. Dans la version actuelle, seuls le volume et le panoramique sont gérés.

\paragraph{``Les'' tempos :}
\label{sec:tempos}
Le tempo d'un fichier midi n'est pas constant. De ce fait, à chaque instruction de nouveau tempo, un nouveau couple \verb?{time,tempo}? est ajouté à la \verb?Hashtable MidiSequence.tempo?

\paragraph{Notes :}
Dans un fichier MIDI, une note est définie par deux instructions : NOTE\_IN et NOTE\_OUT.
\begin{itemize}
\item NOTE\_IN : le couple \verb?{numNote,infosNote}? est stocké dans la \verb?Hashtable? \verb?MidiSequence.buffer?.
\item NOTE\_OUT : une instance de la classe \verb?Note? est créée à partir des deux instructions puis stockée dans la \verb?ArrayList MidiSequence.tracks?.
\end{itemize}
Un objet \verb?Note? contient plusieurs paramètres :
\begin{itemize}
\item index
\item pitch
\item startTime
\item length
\item vol
\item pan
\item numNote (numéro provenant du fichier midi)
\end{itemize}

\subsection{Choix de la chanson et de la piste à jouer}
Au lancement du jeu, chaque fichier midi est analysé et stocké sous forme de \verb?MidiSequence? dans un tableau, puis proposé au joueur dans le menu de choix des niveaux (voir figure \ref{img:menu_songs}). Puis une fois la chanson choisie, le menu affiche la liste des pistes disponibles dans la chanson (voir figure \ref{img:menu_tracks}).

Une fois la piste sélectionnée, la fonction \verb?mapGenerationScript.generateAttracts(MidiSequence midiSequence)? est appelée et le niveau est généré.

\begin{figure}[htbp]
\begin{center}
\includegraphics{img/menu_songs}
\caption{Menu de choix du niveau}
\label{img:menu_songs}
\end{center}
\end{figure}

\begin{figure}[htbp]
\begin{center}
\includegraphics{img/menu_tracks}
\caption{Menu de choix de la piste}
\label{img:menu_tracks}
\end{center}
\end{figure}

\subsection{Création d'une nouvelle instance d'attracteur pour chaque nouvelle note}
Pour chaque nouvelle note dont le départ est supérieur à la note précédente, un nouvel attracteur (voir figure \ref{img:attracts}) est généré puis paramétré en fonction de cette note et en fonction du tempo courant\footnote{voir \ref{sec:tempos}}. Les paramètres sont les suivants :

\begin{figure}[htbp]
\begin{center}
\includegraphics{img/attracts}
\caption{``Attracteurs'' ou ``Planètes'' (actif en bas)}
\label{img:attracts}
\end{center}
\end{figure}

\paragraph{La hauteur de la note :}
mise à jour grâce au pitch calculé grâce à la formule vue en \ref{sec:pitch} (\verb?Note.pitch?)
\paragraph{Durée de la note :}
Le son émit par un attracteur est déclenché lorsque le joueur quitte ce dernier pour viser le suivant. La durée de jeu de la note est représenté par la longueur d'éloignement nécessaire pour que le clip s'arrête (\verb?Note.length?).
\paragraph{Taille :}
relative à durée de la note (\verb?Note.length?).
\paragraph{Position :}
relative à la valeur du temps de départ (\verb?Note.startTime?).
\paragraph{Masse :}
relative à durée de la note (\verb?Note.length?).
\paragraph{Rotation :}
relative à durée de la note (\verb?Note.length?).

\subsection{Ajout de note à un attracteur existant}
Dans une piste, plusieurs notes peuvent être jouées simultanément. Dans le cas où le début de la note courante est égal à celui de la note précédente, le clip audio de la note précédente est copié, puis paramétré.

Les notes ajoutés n'influent pas sur la masse, la taille et la rotation.

\subsection{Activation de la première cible}
Une fois le niveau généré, le premier attracteur est activé et une bulle transparente apparait autour de l'attracteur. Cette bulle représente à peu près la zone d'attraction mais son utilité principale va au delà de l'information graphique. Elle est associée à un \verb?MeshCollider? qui lève un évènement lorsqu'elle est traversé par le joueur. Elle sert donc de ``trigger'';

\paragraph{Gravité :} Effective lorsque l'attracteur est activé, la gravité est gérée grâce à un script basé sur une approximation la loi de l'attraction universelle\footnote{voir figure \ref{form:gravitation}} d'Isaac Newton disponible sur le site \url{http://www.unifycommunity.com/wiki/index.php?title=Gravity}.
\begin{figure}[htbp]
\begin{center}
\begin{equation}
\overrightarrow{F}_{A\rightarrow B} = -G\frac{M_AM_B}{AB^2}\overrightarrow{u}_{AB}
\end{equation}
\caption{Loi de l'attraction universelle}
\label{form:gravitation}
\end{center}
\end{figure}

C'est donc pour cette raison que la masse des attracteurs et du vaisseau a un grand intérêt.

\paragraph{Trigger :}
Une fois déclenché par l'entrée du joueur dans la bulle, il déclenche la fonction \verb?shipControllerScript.enableCurrentOrbitalTrajectory()?. A partir de cet instant, le vaisseau se tourne automatiquement dans le bon sens par rapport au sens de rotation de l'attracteur.
